package com.webshooter.decoder;

import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.json.Json;
import javax.json.stream.JsonParser;
import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;

public class CommandDecoder implements Decoder.Text<Command> {

    private static final String JOIN_COMMAND = "JOIN_COMMAND";
    private static final String KEY_DOWN_COMMAND = "KEY_DOWN_COMMAND";
    private static final String KEY_UP_COMMAND = "KEY_UP_COMMAND";
    private static final String UPDATE_PLAYER_ANGLE_COMMAND = "UPDATE_PLAYER_ANGLE_COMMAND";
    private static final String MOUSE_DOWN_COMMAND = "MOUSE_DOWN_COMMAND";
    private static final String MOUSE_UP_COMMAND = "MOUSE_UP_COMMAND";
    private Map<String, String> commandMap;

    @Override
    public void init(EndpointConfig ec) {
    }

    @Override
    public void destroy() {
    }

    @Override
    public Command decode(String string) throws DecodeException {
        Command command = null;
        if (willDecode(string)) {
            switch (commandMap.get("type")) {
                case JOIN_COMMAND:
                    command = new JoinCommand(commandMap.get("name"));
                    break;
                case KEY_DOWN_COMMAND:
                    command = new KeyPressCommand(commandMap.get("name"), commandMap.get("keyCode"));
                    break;
                case KEY_UP_COMMAND:
                    command = new KeyUpCommand(commandMap.get("name"), commandMap.get("keyCode"));
                    break;
                case UPDATE_PLAYER_ANGLE_COMMAND:
                    command = new UpdatePlayerAngleCommand(commandMap.get("name"), commandMap.get("angle"));
                    break;
                case MOUSE_DOWN_COMMAND:
                    command = new MouseDownCommand(commandMap.get("name"), commandMap.get("mouseButton"), commandMap.get("angle"));
                    break;
                case MOUSE_UP_COMMAND:
                    command = new MouseUpCommand(commandMap.get("name"), commandMap.get("mouseButton"));
                    break;
            }
        } else {
            throw new DecodeException(string, "[Message] Can't decode.");
        }
        return command;
    }

    @Override
    public boolean willDecode(String string) {
        boolean decodes = false;

        commandMap = new HashMap<>();
        fillMessageMap(string);

        Set keys = commandMap.keySet();
        if (keys.contains("type")) {
            switch (commandMap.get("type")) {
                case JOIN_COMMAND:
                    if (keys.contains("name")) {
                        decodes = true;
                    }
                    break;
                case KEY_DOWN_COMMAND:
                    if (keys.contains("keyCode")) {
                        decodes = true;
                    }
                    break;
                case KEY_UP_COMMAND:
                    if (keys.contains("keyCode")) {
                        decodes = true;
                    }
                    break;
                case UPDATE_PLAYER_ANGLE_COMMAND:
                    if (keys.contains("angle")) {
                        decodes = true;
                    }
                    break;
                case MOUSE_DOWN_COMMAND:
                    if (keys.contains("mouseButton") && keys.contains("angle")) {
                        decodes = true;
                    }
                    break;
                case MOUSE_UP_COMMAND:
                    if (keys.contains("mouseButton")) {
                        decodes = true;
                    }
                    break;
            }
        }
        return decodes;
    }

    private void fillMessageMap(String string) {
        JsonParser parser = Json.createParser(new StringReader(string));
        while (parser.hasNext()) {
            if (parser.next() == JsonParser.Event.KEY_NAME) {
                String key = parser.getString();
                parser.next();
                String value = parser.getString();
                commandMap.put(key, value);
            }
        }
    }
}
